#ifndef __ming_fyp_ResourcePool_h__
#define __ming_fyp_ResourcePool_h__

//------------------------------------------------------------------------------
// header includes
#include <map>
#include "fyp/core/String.h"
#include "fyp/core/tuple.h"

#include "fyp/render/Renderable.h"
#include "fyp/render/Shader.h"
#include "fyp/render/Texture.h"
#include "fyp/render/RenderedTexture.h"

//------------------------------------------------------------------------------
namespace ming
{
namespace fyp
{
	namespace render
	{
		class TResourceFactory;

		class IRenderable;
		class IShader;
		class ITexture;
		class IRenderedTexture;
	}

	//--------------------------------------------------------------------------
	class TResourcePool
	{
	public:
		//------------------------------
		// #cstor & #dstor
		TResourcePool(render::TResourceFactory *resFactory);
		~TResourcePool();
		
		//------------------------------
		// external operations
		void RemoveAllResources();

		//------------------------------
		template <class Traits>
		struct Resource_t
		{
			typename Traits::Res* res;
			typename Traits::Param param;
		};

		template <class Traits>
		struct Pool_t : public std::map< TStr, Resource_t<Traits> > {};

		//------------------------------
		// Traits
		template <class T>
		struct Traits_t {};

		template <> struct Traits_t<render::IRenderable> {
			typedef render::IRenderable Res;
			typedef TStr Param;
		};

		template <> struct Traits_t<render::IShader> {
			typedef render::IShader Res;
			typedef tuple<TStr, TStr> Param;
		};

		template <> struct Traits_t<render::ITexture> {
			typedef render::ITexture Res;
			typedef TStr Param;
		};

		template <> struct Traits_t<render::IRenderedTexture> {
			typedef render::IRenderedTexture Res;
			typedef tuple<size_t, size_t, size_t, bool> Param;
		};
		
		//------------------------------
		template<class Res> Pool_t< typename Traits_t<Res> >& Pool();

		template<class Res>
		void Add(
			const TStr &alias, 
			typename Traits_t<Res>::Param const &param);

		//------------------------------
		template<class Res> void Remove(const TStr &alias)
		{
			Pool_t< Traits_t<Res> > &pool = Pool<Res>();

			typename Pool_t< Traits_t<Res> >::iterator iter = pool.find(alias);
			
			if( iter != pool.end() )
			{
				delete iter->second.res;
				pool.erase(iter);
			}
		}

		//------------------------------
		template<class Res> void RemoveByType()
		{
			Pool_t< Traits_t<Res> > &pool = Pool<Res>();

			for(typename Pool_t< Traits_t<Res> >::iterator iter = pool.begin();
				iter != pool.end();
				++iter)
			{
				delete iter->second.res;
			}

			pool.clear();
		}

		//------------------------------
		template<class Res> Res* Get(const TStr &alias)
		{
			return Pool<Res>()[alias].res;
		}

	private:
		//------------------------------
		// internal attributes
		render::TResourceFactory *mResFactory;

		Pool_t< Traits_t<render::IRenderable> > mRenderablePool;
		Pool_t< Traits_t<render::IShader> > mShaderPool;
		Pool_t< Traits_t<render::ITexture> > mTexturePool;
		Pool_t< Traits_t<render::IRenderedTexture> > mRenderedTexPool;

		//------------------------------
		// internal operations

	};
	
	//--------------------------------------------------------------------------
}
}


#endif	//__ming_fyp_ResourcePool_h__